package com.pureut.equipment.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pureut.equipment.domain.MaintenancePlan;
import com.pureut.equipment.domain.MaintenanceProject;
import com.pureut.equipment.domain.PlannedAllocation;
import com.pureut.equipment.domain.dto.MaintenancePlanDto;
import com.pureut.equipment.domain.dto.PlannedAllocationDto;
import com.pureut.equipment.domain.vo.MaintenancePlanVo;
import com.pureut.equipment.domain.vo.MaintenanceWorkOrderVo;
import com.pureut.equipment.domain.vo.RescindVo;
import com.pureut.equipment.domain.vo.ReturnDeviceStatusVo;
import com.pureut.equipment.mapper.MaintenancePlanMapper;
import com.pureut.equipment.mapper.MaintenanceProjectMapper;
import com.pureut.equipment.mapper.PlannedAllocationMapper;
import com.pureut.equipment.service.MaintenancePlanService;
import com.pureut.equipment.service.MaintenanceWorkOrderService;
import com.pureut.equipment.service.PlannedAllocationService;
import com.pureut.equipment.util.TimeUtils;
import com.sale.common.core.exception.GlobalException;
import com.sale.common.dict.utils.DictUtils;
import com.sale.common.mybatis.core.page.PageQuery;
import com.sale.common.mybatis.core.page.TableDataInfo;
import com.sale.common.satoken.utils.LoginHelper;
import com.sale.system.api.RemoteCodeService;
import com.sale.system.api.RemoteDeviceService;
import com.sale.system.api.domain.SysDictData;
import com.sale.system.api.domain.dto.DeviceApiRecordDto;
import com.sale.system.api.domain.vo.ReturnApiDeviceStatusVo;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/***
 *
 * Author: 保养计划 实现层
 * Date:2023/04/23 14:19
 * @DESC
 */
@Service
public class MaintenancePlanServiceImpl extends ServiceImpl<MaintenancePlanMapper, MaintenancePlan> implements MaintenancePlanService {

    /**
     * 保养计划mapper
     */
    @Resource
    MaintenancePlanMapper maintenancePlanMapper;

    /**
     * 计划配置service
     */
    @Resource
    PlannedAllocationService plannedAllocationService;

    /**
     * 计划配置mapper
     */
    @Resource
    PlannedAllocationMapper plannedAllocationMapper;

    /**
     * 保养项目mapper
     */
    @Resource
    MaintenanceProjectMapper maintenanceProjectMapper;

    /**
     * 保养工单mapper
     */
    @Resource
    MaintenanceWorkOrderService maintenanceWorkOrderService;

    @DubboReference
    RemoteCodeService remoteCodeService;

    @DubboReference
    RemoteDeviceService remoteDeviceService;

    /**
     * 保养计划列表
     *
     * @param maintenancePlanVo
     * @return
     */
    @Override
    public TableDataInfo<MaintenancePlanDto> getList(MaintenancePlanVo maintenancePlanVo, PageQuery pageQuery) {
        Page<MaintenancePlanDto> planList = maintenancePlanMapper.getPlanList(maintenancePlanVo, pageQuery.build());
        List<MaintenancePlanDto> records = planList.getRecords();
        //获取状态字典
        List<SysDictData> statusArray = DictUtils.getDictCache("maintenance_plan_status");
        Map<String, String> statusMap = statusArray.stream().collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel));

        //获取计划类型字典
        List<SysDictData> planTypeArray = DictUtils.getDictCache("planned_allocation_plan_type");
        Map<String, String> planTypeMap = planTypeArray.stream().collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel));
        for (MaintenancePlanDto entity : records) {
            entity.setStatusDict(statusMap.get(entity.getStatus()));
            entity.setPlanTypeDict(planTypeMap.get(entity.getPlanType()));
        }
        return TableDataInfo.build(planList);
    }

    /**
     * 新增
     *
     * @param maintenancePlanVo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean add(MaintenancePlanVo maintenancePlanVo) throws Exception {
        //保存采购计划数据
        MaintenancePlan maintenancePlan = new MaintenancePlan();
        String authorityCoding = remoteCodeService.authorityCoding("device:maintenance:plan:list");
        if (authorityCoding == null) {
            throw new GlobalException("该单据未进行配置，无法生成单据编码");
        }
        maintenancePlan.setMaintenancePlanCode(authorityCoding)
            .setStatus(2)
            .setPlanName(maintenancePlanVo.getPlanName())
            .setPlanStartTime(maintenancePlanVo.getPlanStartTime())
            .setPlanEndTime(maintenancePlanVo.getPlanEndTime())
            .setMaintenanceProjectIdStr(maintenancePlanVo.getMaintenanceProjectIdStr())
            .setEquipmentIdStr(maintenancePlanVo.getEquipmentIdStr())
            .setCreateTime(new Date())
            .setCreateBy(LoginHelper.getUsername())
            .setDeptId(LoginHelper.getDeptId());
        boolean isBoolean = save(maintenancePlan);
        if (isBoolean) {
            //保存采购计划对应的计划配置项数据
            PlannedAllocation plannedAllocationData = maintenancePlanVo.getPlannedAllocation();

            PlannedAllocation plannedAllocation = new PlannedAllocation();
            plannedAllocation.setAllocationType(1)
                .setExecutionInterval(plannedAllocationData.getExecutionInterval())
                .setExecutionCycle(plannedAllocationData.getExecutionCycle())
                .setExecutionMonth(plannedAllocationData.getExecutionMonth())
                .setExecutionDays(plannedAllocationData.getExecutionDays())
                .setPlanId(maintenancePlan.getId())
                .setPlanType(plannedAllocationData.getPlanType())
                .setExecutionTime(new Date());
            plannedAllocationService.save(plannedAllocation);
            //同时将配置计划id保存
            MaintenancePlan byId = getById(maintenancePlan.getId());
            byId.setPlannedAllocationId(plannedAllocation.getId());
            updateById(byId);
            //回传设备状态
            ReturnApiDeviceStatusVo returnApiDeviceStatusVo = new ReturnApiDeviceStatusVo();
            returnApiDeviceStatusVo.setDeviceIds(maintenancePlanVo.getEquipmentIdStr());
            returnApiDeviceStatusVo.setStatus(2);
            remoteDeviceService.returnDeviceStatus(returnApiDeviceStatusVo);
        }
        return isBoolean;
    }

    /**
     * 删除
     *
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removePlan(Long id) {
        MaintenancePlan byId = getById(id);
        if (byId.getStatus() != 1) {
            //将计划配置数据删除
            PlannedAllocation plannedAllocation = plannedAllocationMapper.selectOne(new QueryWrapper<PlannedAllocation>().lambda().eq(PlannedAllocation::getPlanId, id).eq(PlannedAllocation::getAllocationType, 1));
            boolean b = plannedAllocationService.removeById(plannedAllocation);
            if (b) {
                //删除保养计划
                removeById(byId);
            }
            return b;
        } else {
            throw new GlobalException("计划启用中，无法删除");
        }
    }


    /**
     * 修改
     *
     * @param maintenancePlanVo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updatePlan(MaintenancePlanVo maintenancePlanVo) {
        MaintenancePlan maintenancePlan = getById(maintenancePlanVo.getId());
        if (maintenancePlan.getStatus() == 2) {
            maintenancePlan.setPlanName(maintenancePlanVo.getPlanName())
                .setPlanStartTime(maintenancePlanVo.getPlanStartTime())
                .setPlanEndTime(maintenancePlanVo.getPlanEndTime())
                .setMaintenanceProjectIdStr(maintenancePlanVo.getMaintenanceProjectIdStr())
                .setEquipmentIdStr(maintenancePlanVo.getEquipmentIdStr());
            boolean b = updateById(maintenancePlan);
            if (b) {
                //获取对应的计划配置数据
                PlannedAllocation plannedAllocation = plannedAllocationMapper.selectOne(new QueryWrapper<PlannedAllocation>().lambda().eq(PlannedAllocation::getId, maintenancePlan.getPlannedAllocationId()));
                PlannedAllocation plannedAllocationData = maintenancePlanVo.getPlannedAllocation();
                plannedAllocation.setExecutionInterval(plannedAllocationData.getExecutionInterval())
                    .setExecutionCycle(plannedAllocationData.getExecutionCycle())
                    .setExecutionMonth(plannedAllocationData.getExecutionMonth())
                    .setExecutionDays(plannedAllocationData.getExecutionDays())
                    .setPlanType(plannedAllocationData.getPlanType());
                plannedAllocationService.updateById(plannedAllocation);
            }
            return b;
        } else {
            throw new GlobalException("只能修改待启用的数据");
        }
    }

    /**
     * 查看
     *
     * @param id
     * @return
     */
    @Override
    public MaintenancePlanDto getView(Long id) {
        MaintenancePlanDto maintenancePlanDto = new MaintenancePlanDto();
        //获取设备类型字典
        List<SysDictData> deviceTypeArray = DictUtils.getDictCache("device_type");
        Map<String, String> deviceTypeMap = deviceTypeArray.stream().collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel));

        //获取计划单数据
        MaintenancePlan maintenancePlan = getById(id);
        //获取对应的计划配置数据
        PlannedAllocation plannedAllocation = plannedAllocationMapper.selectOne(new QueryWrapper<PlannedAllocation>().lambda().eq(PlannedAllocation::getId, maintenancePlan.getPlannedAllocationId()).eq(PlannedAllocation::getAllocationType, 1));

        //获取保养项目
        List<String> projectIds = Arrays.asList(maintenancePlan.getMaintenanceProjectIdStr().split(","));
        List<MaintenanceProject> maintenanceProjects = maintenanceProjectMapper.selectList(new QueryWrapper<MaintenanceProject>().lambda().in(MaintenanceProject::getId, projectIds));
        maintenancePlanDto.setMaintenanceProjects(maintenanceProjects);
        //获取关联设备
        String ids = maintenancePlan.getEquipmentIdStr();
        List<DeviceApiRecordDto> drvices = remoteDeviceService.getDeviceByIds(ids);
        for (DeviceApiRecordDto entity : drvices) {
            //设备类型
            entity.setDeviceTypeDict(deviceTypeMap.get(entity.getDeviceType()));
        }
        maintenancePlanDto.setDrvices(drvices);
        //封装计划配置项
        PlannedAllocationDto plannedAllocationDto = new PlannedAllocationDto();
        //执行周期列表
        List<String> cycleList = Arrays.asList(plannedAllocation.getExecutionCycle().split(","));
        //执行月份列表
        List<String> monthList = Arrays.asList(plannedAllocation.getExecutionMonth().split(","));
        //执行日期列表
        List<String> daysList = Arrays.asList(plannedAllocation.getExecutionDays().split(","));

        plannedAllocationDto.setId(plannedAllocation.getId())
            .setPlanId(plannedAllocation.getPlanId())
            .setExecutionInterval(plannedAllocation.getExecutionInterval())
            .setPlanType(plannedAllocation.getPlanType())
            .setExecutionCycleList(cycleList)
            .setExecutionMonthList(monthList)
            .setExecutionDaysList(daysList);
        maintenancePlanDto.setId(maintenancePlan.getId());
        maintenancePlanDto.setPlannedAllocationDto(plannedAllocationDto);
        maintenancePlanDto.setMaintenancePlanCode(maintenancePlan.getMaintenancePlanCode());
        maintenancePlanDto.setPlanName(maintenancePlan.getPlanName());
        maintenancePlanDto.setPlanStartTime(maintenancePlan.getPlanStartTime());
        maintenancePlanDto.setPlanEndTime(maintenancePlan.getPlanEndTime());

        return maintenancePlanDto;
    }

    /**
     * 启用
     *
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean enable(Long id) throws Exception {
        MaintenancePlan maintenancePlan = getById(id);
        long timeStart = maintenancePlan.getPlanStartTime().getTime();
        long timeEnd = maintenancePlan.getPlanEndTime().getTime();
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");

        Date nowParse = simpleDateFormat.parse(simpleDateFormat.format(date));
        long timeNow = nowParse.getTime();
        //如果当前时间大于计划结束时间，就变为已结束；如果当前时间小于计划开始时间，就变为未开始
        if (timeNow > timeEnd) {
            maintenancePlan.setStatus(4);
            return updateById(maintenancePlan);
        }
        if (timeNow < timeStart) {
            maintenancePlan.setStatus(5);
            return updateById(maintenancePlan);
        }
        if (maintenancePlan.getStatus() == 3 || maintenancePlan.getStatus() == 2) {
            maintenancePlan.setStatus(1);
            PlannedAllocation plannedAllocation = plannedAllocationMapper.selectOne(new QueryWrapper<PlannedAllocation>().lambda().eq(PlannedAllocation::getId, maintenancePlan.getPlannedAllocationId()).eq(PlannedAllocation::getAllocationType, 1));
            // 若计划类型为”日”时，则在启用时立即执行一次；
            if (plannedAllocation.getPlanType() == 1) {
                if (maintenancePlan.getStatus() != 3) {
                    //如果当前时间在计划时间之内
                    if (timeNow >= timeStart && timeNow <= timeEnd) {
                        //生成保养工单
                        MaintenanceWorkOrderVo maintenanceWorkOrderVo = new MaintenanceWorkOrderVo();
                        maintenanceWorkOrderVo.setMaintenanceProjectIdStr(maintenancePlan.getMaintenanceProjectIdStr());
                        maintenanceWorkOrderVo.setDeviceIds(maintenancePlan.getEquipmentIdStr());
                        maintenanceWorkOrderVo.setSubordinatePlan(maintenancePlan.getId());
                        maintenanceWorkOrderService.addToday(maintenanceWorkOrderVo);
                    }
                }
            }
            // 若计划类型为周时
            if (plannedAllocation.getPlanType() == 2) {
                //获取每周执行的字符串时间
                List<String> executionCycle = Arrays.asList(plannedAllocation.getExecutionCycle().split(","));
                //获取当前时间是星期几
                String i = String.valueOf(TimeUtils.dayForWeek(simpleDateFormat.format(new Date())));
                //如果当前星期几包含在周执行天数
                if (executionCycle.contains(i)) {
                    //如果可以整除，就生成对应的保养工单
                    MaintenanceWorkOrderVo maintenanceWorkOrderVo = new MaintenanceWorkOrderVo();
                    maintenanceWorkOrderVo.setMaintenanceProjectIdStr(maintenancePlan.getMaintenanceProjectIdStr());
                    maintenanceWorkOrderVo.setDeviceIds(maintenancePlan.getEquipmentIdStr());
                    maintenanceWorkOrderVo.setSubordinatePlan(maintenancePlan.getId());
                    maintenanceWorkOrderService.addScheduling(maintenanceWorkOrderVo);
                }
            }
            // 若计划类型为月时
            if (plannedAllocation.getPlanType() == 3) {
                List<String> monthList = Arrays.asList(plannedAllocation.getExecutionMonth().split(","));
                List<String> dayList = Arrays.asList(plannedAllocation.getExecutionDays().split(","));
                StringBuilder stringBuilder = new StringBuilder();
                for (String entityMonth : monthList) {
                    for (String entityDay : dayList) {
                        BigDecimal add = new BigDecimal(entityDay).add(new BigDecimal("1"));
                        stringBuilder.append(entityMonth).append("-").append(add).append(",");
                    }
                }
                StringBuilder dateResult = stringBuilder.deleteCharAt(stringBuilder.length() - 1);
                //获取当前时间
                SimpleDateFormat sf = new SimpleDateFormat("MM-dd");
                String format = sf.format(new Date());
                //判断当前时间是否在计划开始时间和计划结束时间之内
                boolean effectiveDate = TimeUtils.isEffectiveDate(new Date(), maintenancePlan.getPlanStartTime(), maintenancePlan.getPlanEndTime());
                if (dateResult.toString().contains(format) && effectiveDate) {
                    MaintenanceWorkOrderVo maintenanceWorkOrderVo = new MaintenanceWorkOrderVo();
                    maintenanceWorkOrderVo.setMaintenanceProjectIdStr(maintenancePlan.getMaintenanceProjectIdStr());
                    maintenanceWorkOrderVo.setDeviceIds(maintenancePlan.getEquipmentIdStr());
                    maintenanceWorkOrderVo.setSubordinatePlan(maintenancePlan.getId());
                    maintenanceWorkOrderService.addScheduling(maintenanceWorkOrderVo);
                }
            }
            return updateById(maintenancePlan);
        } else {
            throw new GlobalException("只能启用状态为”已停用”或者“待启用”的计划");
        }
    }

    /**
     * 停用
     *
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean stop(Long id) {
        MaintenancePlan maintenancePlan = getById(id);
        if (maintenancePlan.getStatus() == 1 || maintenancePlan.getStatus() == 5) {
            maintenancePlan.setStatus(3);
            return updateById(maintenancePlan);
        } else {
            throw new GlobalException("只能停用状态为”启用中”或“未开始”的计划");
        }
    }

    /**
     * 解除关联
     *
     * @param rescindVo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean rescind(RescindVo rescindVo) {

        MaintenancePlan maintenancePlan = getById(rescindVo.getId());
        //获取关联的设备id
        List<String> equipmentIdList = Arrays.asList(maintenancePlan.getEquipmentIdStr().split(","));
        //删除相关设备id
        boolean b = equipmentIdList.removeIf(entity -> entity.equals(String.valueOf(rescindVo.getDeviceId())));
        if (b) {
            StringBuilder stringBuilder = new StringBuilder();
            for (String entity : equipmentIdList) {
                stringBuilder.append(entity).append(",");
            }
            stringBuilder.deleteCharAt(stringBuilder.length() - 1);
            maintenancePlan.setEquipmentIdStr(stringBuilder.toString());
            return updateById(maintenancePlan);
        }
        return b;
    }

    /**
     * 根据计划开始时间和结束时间定时修改计划状态（定时任务调用）
     *
     * @return
     */
    @Override
    public boolean updateMaintenanceStatusByTime() throws ParseException {
        List<MaintenancePlan> list = list();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date date = new Date();
        Date nowParse = simpleDateFormat.parse(simpleDateFormat.format(date));
        long nowTime = nowParse.getTime();
        for (MaintenancePlan entity : list) {
            long planEndTime = entity.getPlanEndTime().getTime();
            long planStartTime = entity.getPlanStartTime().getTime();
            if (nowTime < planStartTime || nowTime > planEndTime) {
                entity.setStatus(4);
            }
        }
        return updateBatchById(list);
    }
}
